{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can download the `requirements.txt` for this course from the workspace of this lab. `File --> Open...`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# L2: Create Agents to Research and Write an Article\n",
    "\n",
    "In this lesson, you will be introduced to the foundational concepts of multi-agent systems and get an overview of the crewAI framework."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The libraries are already installed in the classroom. If you're running this notebook on your own machine, you can install the following:\n",
    "```Python\n",
    "!pip install crewai==0.28.8 crewai_tools==0.1.6 langchain_community==0.0.29\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "height": 63
   },
   "outputs": [],
   "source": [
    "# Warning control\n",
    "import warnings\n",
    "warnings.filterwarnings('ignore')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- Import from the crewAI libray."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": [
    "from crewai import Agent, Task, Crew"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- As a LLM for your agents, you'll be using OpenAI's `gpt-3.5-turbo`.\n",
    "\n",
    "**Optional Note:** crewAI also allow other popular models to be used as a LLM for your Agents. You can see some of the examples at the [bottom of the notebook](#1)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "height": 97
   },
   "outputs": [],
   "source": [
    "import os\n",
    "from utils import get_openai_api_key\n",
    "\n",
    "openai_api_key = get_openai_api_key()\n",
    "os.environ[\"OPENAI_MODEL_NAME\"] = 'gpt-3.5-turbo'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Creating Agents\n",
    "\n",
    "- Define your Agents, and provide them a `role`, `goal` and `backstory`.\n",
    "- It has been seen that LLMs perform better when they are role playing."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Agent: Planner\n",
    "\n",
    "**Note**: The benefit of using _multiple strings_ :\n",
    "```Python\n",
    "varname = \"line 1 of text\"\n",
    "          \"line 2 of text\"\n",
    "```\n",
    "\n",
    "versus the _triple quote docstring_:\n",
    "```Python\n",
    "varname = \"\"\"line 1 of text\n",
    "             line 2 of text\n",
    "          \"\"\"\n",
    "```\n",
    "is that it can avoid adding those whitespaces and newline characters, making it better formatted to be passed to the LLM."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "height": 250
   },
   "outputs": [],
   "source": [
    "planner = Agent(\n",
    "    role=\"Content Planner\",\n",
    "    goal=\"Plan engaging and factually accurate content on {topic}\",\n",
    "    backstory=\"You're working on planning a blog article \"\n",
    "              \"about the topic: {topic}.\"\n",
    "              \"You collect information that helps the \"\n",
    "              \"audience learn something \"\n",
    "              \"and make informed decisions. \"\n",
    "              \"Your work is the basis for \"\n",
    "              \"the Content Writer to write an article on this topic.\",\n",
    "    allow_delegation=False,\n",
    "\tverbose=True\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Agent: Writer"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "height": 386
   },
   "outputs": [],
   "source": [
    "writer = Agent(\n",
    "    role=\"Content Writer\",\n",
    "    goal=\"Write insightful and factually accurate \"\n",
    "         \"opinion piece about the topic: {topic}\",\n",
    "    backstory=\"You're working on a writing \"\n",
    "              \"a new opinion piece about the topic: {topic}. \"\n",
    "              \"You base your writing on the work of \"\n",
    "              \"the Content Planner, who provides an outline \"\n",
    "              \"and relevant context about the topic. \"\n",
    "              \"You follow the main objectives and \"\n",
    "              \"direction of the outline, \"\n",
    "              \"as provide by the Content Planner. \"\n",
    "              \"You also provide objective and impartial insights \"\n",
    "              \"and back them up with information \"\n",
    "              \"provide by the Content Planner. \"\n",
    "              \"You acknowledge in your opinion piece \"\n",
    "              \"when your statements are opinions \"\n",
    "              \"as opposed to objective statements.\",\n",
    "    allow_delegation=False,\n",
    "    verbose=True\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Agent: Editor"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "height": 284
   },
   "outputs": [],
   "source": [
    "editor = Agent(\n",
    "    role=\"Editor\",\n",
    "    goal=\"Edit a given blog post to align with \"\n",
    "         \"the writing style of the organization. \",\n",
    "    backstory=\"You are an editor who receives a blog post \"\n",
    "              \"from the Content Writer. \"\n",
    "              \"Your goal is to review the blog post \"\n",
    "              \"to ensure that it follows journalistic best practices,\"\n",
    "              \"provides balanced viewpoints \"\n",
    "              \"when providing opinions or assertions, \"\n",
    "              \"and also avoids major controversial topics \"\n",
    "              \"or opinions when possible.\",\n",
    "    allow_delegation=False,\n",
    "    verbose=True\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Creating Tasks\n",
    "\n",
    "- Define your Tasks, and provide them a `description`, `expected_output` and `agent`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Task: Plan"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "height": 284
   },
   "outputs": [],
   "source": [
    "plan = Task(\n",
    "    description=(\n",
    "        \"1. Prioritize the latest trends, key players, \"\n",
    "            \"and noteworthy news on {topic}.\\n\"\n",
    "        \"2. Identify the target audience, considering \"\n",
    "            \"their interests and pain points.\\n\"\n",
    "        \"3. Develop a detailed content outline including \"\n",
    "            \"an introduction, key points, and a call to action.\\n\"\n",
    "        \"4. Include SEO keywords and relevant data or sources.\"\n",
    "    ),\n",
    "    expected_output=\"A comprehensive content plan document \"\n",
    "        \"with an outline, audience analysis, \"\n",
    "        \"SEO keywords, and resources.\",\n",
    "    agent=planner,\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Task: Write"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "height": 318
   },
   "outputs": [],
   "source": [
    "write = Task(\n",
    "    description=(\n",
    "        \"1. Use the content plan to craft a compelling \"\n",
    "            \"blog post on {topic}.\\n\"\n",
    "        \"2. Incorporate SEO keywords naturally.\\n\"\n",
    "\t\t\"3. Sections/Subtitles are properly named \"\n",
    "            \"in an engaging manner.\\n\"\n",
    "        \"4. Ensure the post is structured with an \"\n",
    "            \"engaging introduction, insightful body, \"\n",
    "            \"and a summarizing conclusion.\\n\"\n",
    "        \"5. Proofread for grammatical errors and \"\n",
    "            \"alignment with the brand's voice.\\n\"\n",
    "    ),\n",
    "    expected_output=\"A well-written blog post \"\n",
    "        \"in markdown format, ready for publication, \"\n",
    "        \"each section should have 2 or 3 paragraphs.\",\n",
    "    agent=writer,\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Task: Edit"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "height": 182
   },
   "outputs": [],
   "source": [
    "edit = Task(\n",
    "    description=(\"Proofread the given blog post for \"\n",
    "                 \"grammatical errors and \"\n",
    "                 \"alignment with the brand's voice.\"),\n",
    "    expected_output=\"A well-written blog post in markdown format, \"\n",
    "                    \"ready for publication, \"\n",
    "                    \"each section should have 2 or 3 paragraphs.\",\n",
    "    agent=editor\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Creating the Crew\n",
    "\n",
    "- Create your crew of Agents\n",
    "- Pass the tasks to be performed by those agents.\n",
    "    - **Note**: *For this simple example*, the tasks will be performed sequentially (i.e they are dependent on each other), so the _order_ of the task in the list _matters_.\n",
    "- `verbose=2` allows you to see all the logs of the execution. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "height": 97
   },
   "outputs": [],
   "source": [
    "crew = Crew(\n",
    "    agents=[planner, writer, editor],\n",
    "    tasks=[plan, write, edit],\n",
    "    verbose=2\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Running the Crew"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Note**: LLMs can provide different outputs for they same input, so what you get might be different than what you see in the video."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "height": 46
   },
   "outputs": [],
   "source": [
    "result = crew.kickoff(inputs={\"topic\": \"Artificial Intelligence\"})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- Display the results of your execution as markdown in the notebook."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "height": 46
   },
   "outputs": [],
   "source": [
    "from IPython.display import Markdown\n",
    "Markdown(result)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Try it Yourself\n",
    "\n",
    "- Pass in a topic of your choice and see what the agents come up with!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "height": 46
   },
   "outputs": [],
   "source": [
    "topic = \"YOUR TOPIC HERE\"\n",
    "result = crew.kickoff(inputs={\"topic\": topic})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": [
    "Markdown(result)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a name='1'></a>\n",
    " ## Other Popular Models as LLM for your Agents"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Hugging Face (HuggingFaceHub endpoint)\n",
    "\n",
    "```Python\n",
    "from langchain_community.llms import HuggingFaceHub\n",
    "\n",
    "llm = HuggingFaceHub(\n",
    "    repo_id=\"HuggingFaceH4/zephyr-7b-beta\",\n",
    "    huggingfacehub_api_token=\"<HF_TOKEN_HERE>\",\n",
    "    task=\"text-generation\",\n",
    ")\n",
    "\n",
    "### you will pass \"llm\" to your agent function\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Mistral API\n",
    "\n",
    "```Python\n",
    "OPENAI_API_KEY=your-mistral-api-key\n",
    "OPENAI_API_BASE=https://api.mistral.ai/v1\n",
    "OPENAI_MODEL_NAME=\"mistral-small\"\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Cohere\n",
    "\n",
    "```Python\n",
    "from langchain_community.chat_models import ChatCohere\n",
    "# Initialize language model\n",
    "os.environ[\"COHERE_API_KEY\"] = \"your-cohere-api-key\"\n",
    "llm = ChatCohere()\n",
    "\n",
    "### you will pass \"llm\" to your agent function\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### For using Llama locally with Ollama and more, checkout the crewAI documentation on [Connecting to any LLM](https://docs.crewai.com/how-to/LLM-Connections/)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "colab": {
   "gpuType": "T4",
   "provenance": []
  },
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
